#include <system/syscall.h>
#include <interrupt/idt.h>
#include <system/regs.h>
#include <klibc/stdio.h>
#include <fs/vfscall.h>
#include <net/net.h>

extern void syscallisr();

/*
 * Effetua una chiamata ad una call
 */
void syscall_call(uint32_t call, uint32_t ebx, uint32_t ecx, uint32_t edx)
{
	asm ("movl %0, %%eax\n\t"
		 "movl %1, %%ebx\n\t"
		 "movl %2, %%ecx\n\t"
		 "movl %3, %%edx\n\t"
		 : : "g" (call), "g" (ebx), "g" (ecx), "g" (edx));	
	asm ("int $84");
}


/*
 * Handler delle chiamate alla syscall
 */
void syscall_callback(regs_t *r)
{	
	regs_t reg;
	int ret;
	
	asm ("cli");

	// Preleva gli argomenti (provvisorio)
	asm ("movl %%eax, %0\n\t"
		 "movl %%ebx, %1\n\t"
		 "movl %%ecx, %2\n\t"
		 "movl %%edx, %3\n\t"
		 : "=r" (reg.eax), "=r" (reg.ebx), "=r" (reg.ecx), "=r" (reg.edx));
	  
	printf("Syscall: %d -> ", reg.eax);
	
	switch(reg.eax)
	{
		/*
		 * Chiamate per il vfs
		 *//*
		case SYSCALL_FS_FOPEN:
			ret = (int32_t) fs_fopen((char *) reg.ebx, (char *) reg.ecx);
			break;
				
		case SYSCALL_FS_FCLOSE:
			fs_fclose((int32_t) reg.ebx); 
			break;
				
		case SYSCALL_FS_FREAD:
			ret = fs_fread((int32_t) reg.ebx, (uint32_t) reg.ecx, (char *) reg.edx);
			break;
				
		case SYSCALL_FS_FWRITE:
			ret = fs_fwrite((int32_t) reg.ebx, (uint32_t) reg.ecx, (char *) reg.edx);
			break;
				
		case SYSCALL_FS_FSTAT:
			fs_fstat((int32_t) reg.ebx, (struct stat *) reg.ecx);
			break;
				
		case SYSCALL_FS_REMOVE:
			ret = fs_remove((char *) reg.ebx);
			break;
				
		case SYSCALL_FS_LINK:
			ret = fs_link((char *) reg.ebx, (char *) reg.ecx);
			break;
				
		case SYSCALL_FS_UNLINK:
			ret = fs_unlink((char *) reg.ebx);
			break;
				
		case SYSCALL_FS_MOUNT:
			ret = fs_mount((char *) reg.ebx, (char *) reg.ecx, (char *) reg.edx); 
			break;
				
		case SYSCALL_FS_UMOUNT:
			ret = fs_umount((char *) reg.ebx); 
			break;
				
		case SYSCALL_FS_MAKEDIR:
			ret = fs_makedir((char *) reg.ebx);
			break;
				
		case SYSCALL_FS_STAT:
			fs_stat((char *) reg.ebx, (struct stat *) reg.ecx);
			break;
				*/
				
		/*
		 * Chiamate per i task
		 */
		case SYSCALL_TASK_EXIT:
			printf("TASK_EXIT! Not yet implemented\n");  
			break;
			
		case SYSCALL_TASK_FORK:
			printf("TASK_FORK! Not yet implemented\n");  
			break;
			
		case SYSCALL_TASK_GETPID:
			printf("TASK_GETPID! Not yet implemented\n");  
			break;
			
		case SYSCALL_TASK_IN:
			printf("TASK_IN! Not yet implemented\n");  
			break;
			
		case SYSCALL_TASK_OUT:
			printf("TASK_OUT! Not yet implemented\n");  
			break;
			
		case SYSCALL_TASK_SBRK:
			printf("TASK_SBRK! Not yet implemented\n");  
			break;
			
		case SYSCALL_TASK_EXEC:
			printf("TASK_EXEC! Not yet implemented\n");  
			break;
			

		/*
		 * Chiamate per il network
		 */
		case SYSCALL_NET_ACCEPT: 
			ret = net_accept((int32_t) reg.ebx, (struct sockaddr *) reg.ecx, (int32_t *) reg.edx);
			break;
			
		case SYSCALL_NET_BIND:
			ret = net_bind((int32_t) reg.ebx, (struct sockaddr *) reg.ecx, (int32_t) reg.edx);
			break;
			
		case SYSCALL_NET_CLOSE:
			ret = net_close((int32_t) reg.ebx);
			break;
			
		case SYSCALL_NET_CONNECT:
			ret = net_connect((int32_t) reg.ebx, (struct sockaddr *) reg.ecx, (int32_t) reg.edx);
			break;
			
		case SYSCALL_NET_LISTEN:
			ret = net_listen((int32_t) reg.ebx, (int32_t) reg.ecx);
			break;
			
		case SYSCALL_NET_RECV:
			printf("NET_RECV! Not yet implemented\n");  
			break;
			
		case SYSCALL_NET_SEND:
			printf("NET_SEND! Not yet implemented\n");  
			break;
			
		case SYSCALL_NET_SOCKET:
			ret = net_socket((int32_t) reg.ebx, (int32_t) reg.ecx, (int32_t) reg.edx);
			break;
			
			
		/*
		 * Chiamate di sistema
		 */			
		case SYSCALL_SYS_OUT:
			printf("SYS_OUT: '");  
			putchar(reg.ebx);
			printf("'\n");
			break;
			
		case SYSCALL_SYS_SHUTDOWN:
			spiderpig_shutdown();
			break;
			
		default:
			printf("Not valid.\n");
	}
	
	
	/*
	 * Restituisce il valore di ritorno
	 */
	
	asm ("sti");
}



/*
 * Inizializza le syscall
 */
uint32_t syscall_init()
{
    idt_set_gate(84, (unsigned)syscallisr, 0x08, 0x8E);
}


uint32_t syscall_shut()
{
    idt_set_gate(84, (unsigned)NULL, 0x08, 0x8E);
}

